采用迁移学习进行物体识别

山东理工大学 数学院 周世祥 shixiangbupt@qq.com
  1. 什么是迁移学习
站在巨人的肩上,“举一反三”,“触类旁通”,学会了C语言,也很快就学会了matlab,异曲同工。
把一个领域的知识,迁移到另一个领域,基于共享参数的迁移学习,以经典的卷积网络为基础,通过修改一个已经训练好的深度卷积网络的最后几层连接层,再使用对特定问题而建立的小数据集进行训练,以使其适用于一个新问题。
案例:对AlexNet网络进行改进,并用样本数据进行训练,实现对输入图像的识别。
%% 程序说明
% 实例
% 功能:基于共享参数的迁移学习的原理,对AlexNet进行改进,并用样本数据进行训练,实现对输入图像的识别
第二天再试试
% 作者:zhaoxch_mail@sina.com
% 时间:2020年3月1日
% 版本:DLTEX4-V1
% 注:本程序主要是用于说明基于迁移学习的原理,如何将已训练好的经典网络进行改进并进行训练,请重点关注步骤3、步骤4。
%% 步骤1:加载图像数据,并将其划分为训练集和验证集
% 加载图像数据
unzip('MerchData.zip');
imds = imageDatastore('MerchData', ...
'IncludeSubfolders',true, ...
'LabelSource','foldernames');
% 划分验证集和训练集
[imdsTrain,imdsValidation] = splitEachLabel(imds,0.7,'randomized');
% 随机显示训练集中的部分图像
numTrainImages = numel(imdsTrain.Labels);
idx = randperm(numTrainImages,16);
figure
for i = 1:16
subplot(4,4,i)
I = readimage(imdsTrain,idx(i));
imshow(I)
end
%% 步骤2:加载预训练好的网络
% 加载alexnet网络(注:该网络需要提前下载,当输入下面命令时按要求下载即可)
net = alexnet;
%% 步骤3:对网络结构进行改进
% 保留AlexNet倒数第三层之前的网络
layersTransfer = net.Layers(1:end-3);
% 确定训练数据中需要分类的种类
numClasses = numel(categories(imdsTrain.Labels));
% 构建新的网络,保留AlexNet倒数第三层之前的网络,在此之后重新添加了全连接
layers = [
layersTransfer % 保留AlexNet倒数第三层之前的网络
fullyConnectedLayer(numClasses) % 将新的全连接层的输出设置为训练数据中的种类
softmaxLayer % 添加新的Softmax层
classificationLayer ]; % 添加新的分类层
%% 步骤4:调整数据集
% 查看网络输入层的大小和通道数
inputSize = net.Layers(1).InputSize;
% 将训练图像的大小调整为与输入层的大小相同
augimdsTrain = augmentedImageDatastore(inputSize(1:2),imdsTrain);
% 将验证图像的大小调整为与输入层的大小相同
augimdsValidation = augmentedImageDatastore(inputSize(1:2),imdsValidation);
%% 对网络进行训练
% 对训练参数进行设置
options = trainingOptions('sgdm', ...
'MiniBatchSize',15, ...
'MaxEpochs',10, ...
'InitialLearnRate',0.00005, ...
'Shuffle','every-epoch', ...
'ValidationData',augimdsValidation, ...
'ValidationFrequency',3, ...
'Verbose',true, ...
'Plots','training-progress');
% 用训练图像对网络进行训练
netTransfer = trainNetwork(augimdsTrain,layers,options);
在单 GPU 上训练。 正在初始化输入数据归一化。 |=============================================================================| |  轮  |  迭代  |    经过的时间     |  小批量准确度  |  验证准确度  |  小批量损失  |  验证损失  |  基础学习率  | |     |      |  (hh:mm:ss)  |          |         |         |        |         | |=============================================================================| |   1 |    1 |     00:00:04 |   20.00% |  10.00% |  3.5665 | 2.4579 | 5.0000e-05 | |   1 |    3 |     00:00:04 |    6.67% |  25.00% |  4.5968 | 1.9925 | 5.0000e-05 | |   2 |    6 |     00:00:05 |   26.67% |  50.00% |  2.9358 | 1.2960 | 5.0000e-05 | |   3 |    9 |     00:00:05 |   40.00% |  70.00% |  1.8389 | 0.8930 | 5.0000e-05 | |   4 |   12 |     00:00:06 |   40.00% |  80.00% |  2.4903 | 0.6268 | 5.0000e-05 | |   5 |   15 |     00:00:06 |   86.67% |  85.00% |  0.5530 | 0.4274 | 5.0000e-05 | |   6 |   18 |     00:00:06 |   86.67% |  95.00% |  0.5176 | 0.2976 | 5.0000e-05 | |   7 |   21 |     00:00:07 |   86.67% |  95.00% |  0.3129 | 0.2067 | 5.0000e-05 | |   8 |   24 |     00:00:07 |   93.33% | 100.00% |  0.2362 | 0.1526 | 5.0000e-05 | |   9 |   27 |     00:00:07 |   93.33% | 100.00% |  0.1893 | 0.1197 | 5.0000e-05 | |  10 |   30 |     00:00:08 |  100.00% | 100.00% |  0.0172 | 0.1009 | 5.0000e-05 | |=============================================================================|
%% 分类验证图像并并随机显示分类结果
% 对训练好的网络采用验证数据集进行验证
[YPred,scores] = classify(netTransfer,augimdsValidation);
% 随机显示验证效果
idx = randperm(numel(imdsValidation.Files),4);
figure
for i = 1:4
subplot(2,2,i)
I = readimage(imdsValidation,idx(i));
imshow(I)
label = YPred(idx(i));
title(string(label));
end
%% 计算分类准确率
YValidation = imdsValidation.Labels;
accuracy = mean(YPred == YValidation)
accuracy =
1
%% 创建并显示混淆矩阵
figure
confusionchart(YValidation,YPred)
ans =
ConfusionMatrixChart - 属性: NormalizedValues: [5×5 double] ClassLabels: [5×1 categorical] 显示 所有属性
预训练好的Alex net网络的最后3层原本为用对1000个类别的物体进行识别,新的分类问题必须调整这3层。
先从预训练网络中取出除最后这三层外的所有层,然后用一个全连接层,一个softmax层和一个分类层替换最后3层。
由于AlexNet需要输入图像大小为227*227*3像素,因此还需要对训练图像的大小及验证数据的图像大小不同用函数augmentedImageDatastore()进行批量调整。
创建混淆矩阵:confusionchart()
矩阵行对应真实类,列对应预测类,对角线对应正确分类的个数,非对角线对应错误分类的个数。
心理学上,对某一项技能的学习能对其他技能产生积极的影响,迁移学习效应,人工智能研究领域之一。
卷积神经网络在进行物体识别过程中,可以自动提取特征并根据特征进行分类。
仿生学上,模仿大脑皮层工作原理的深度神经网络,卷积神经网络提取的特征是一层层抽象的,越是底层的特征越基本,底层的卷积层学习到角点,边缘,颜色,纹理等共性特征,越是高层越抽象越复杂,到了顶层附近学习到了特征可以大概描述一个物体了,这样的抽象特征又称语义特征。
在一些任务中,可用于训练的数据样本很少,如果从头训练一个卷积神经网络模型,效果不是很好,此时,可利用别人已经训练好的卷积神经网络模型,然后尝试改变该模型语义层的参数即可。
前面是共性,后面是个性,从统计意义上讲。

采用Deep Network Designer实现卷积网络设计

matlab中提供了一个便于设计,查看,检验深度网络的工具Deep network designer.
有两种打开方式,在命令窗口中,输入代码:
deepNetworkDesigner
第二种方式:
用菜单方式,从APP中打开
下面的案例,构建一个卷积网络,实现对输入的含有数字0~9的二值图像28*28进行分类,并计算分类的准确率。

网络架构

输入:28*28像素,1个通道
卷积1:卷积核大小3*3,个数为32个,0填充方式(same)
批量归一化层1:加快训练时网络收敛速度;
非线性激励函数1:用ReLU 函数
池化层1:最大池化,2*2,步长1
卷积2:3*3,个数为32个,0填充方式(same)
批量归一化层2:
非线性激励函数2:用ReLU 函数
池化层1:最大池化,2*2,步长2
全连接层2:输出为10个
softmax层:得出全连接层每一个输出的概率
分类层:根据概率判断类别

步骤

步骤1:从模块库中将Image input layer模块拖到操作区中,单击该模块,在右侧属性显示区中进行参数设置,将其设置为输入图像大小28*28,1个通道。
步骤2:从模块库中将Convolution2DLayer模块拖到操作区中,单击该模块,在右侧属性显示区中对其进行参数设置,将其设置为:卷积核大小为3*3,卷积核的个数为32(每个卷积核1个通道),卷积的方式采用零填充方式,即same方式,其他采用默认设置。
步骤3:从模块库中将BatchNormalizationLayer拖到操作区中,单击该模块,在右侧属性显示区中对其进行参数设置,一般采用默认。
步骤4:从模块库中将ReLULayer模块拖到操作区中。
步骤5:从模块库中将MaxPooling2DLayer模块拖到操作区中,单击该模块,在右侧属性显示区中对其进行参数设置,将其设置为:池化区域为2*2,步长为1,其他采用默认设置。
步骤6:按第1到5步的方式,构建卷积层2,批量归一化层2,非线性激活函数2,最大池化层2,参数见前一节。
步骤7:从模块库中将FullyConnectedLayer模块拖到操作区中,单击该模块,在右侧属性显示区中对其进行参数设置,将其设置为:输出的个数10个,其他采用默认的设置。
步骤8:从模块库中将SoftmaxLayer拖到操作区中。
步骤9:从模块库中将ClassificationOutputLayer拖到操作区;
步骤10:将各层顺序依次连接;
步骤11:单击控制面板上的Analyze按钮,对所设计的网络进行检查,检查结果如图。
步骤12:单击导出Export,会将网络导出到工作区workspace,并默认名layers_1
步骤13:对于导出到工作区的卷积神经网络,在工作区中将其选中,通过右键快捷菜单将其重命名为covnet1

对网络进行训练与验证

训练方法为'sgdm',初始学习率为0.0005,最大轮数为6,每轮训练都随机打乱数据,验证频率为30次/轮。
在配置过程中,将'Verbose'设置为true,所以该网络的训练核验证过程也在命令窗口中显示。
%% 程序说明
% 实例 4.4-1
% 功能:对covnet1卷积神经网路进行训练
% 作者:
% 时间:2020年3月7日
% 版本:DLTEX4-V1
%% 步骤1:加载图像样本数据,并显示其中的部分图像
digitDatasetPath = fullfile(matlabroot,'toolbox','nnet','nndemos', ...
'nndatasets','DigitDataset');
imds = imageDatastore(digitDatasetPath, ...
'IncludeSubfolders',true,'LabelSource','foldernames');
figure;
perm = randperm(10000,20);
for i = 1:20
subplot(4,5,i);
imshow(imds.Files{perm(i)});
end
%% 步骤2:将加载的图像样本分为训练集和测试集(注:在本例中,训练集的数量为750幅,剩余的为测试集)
numTrainFiles = 750;
[imdsTrain,imdsValidation] = splitEachLabel(imds,numTrainFiles,'randomize');
%% 步骤3:配置训练选项并开始训练
% 配置训练选项
options = trainingOptions('sgdm', ...
'InitialLearnRate',0.0005, ...
'MaxEpochs',6, ...
'Shuffle','every-epoch', ...
'ValidationData',imdsValidation, ...
'ValidationFrequency',30, ...
'Verbose',true, ... %显示训练过程
'Plots','training-progress');
% 对网络进行训练
net = trainNetwork(imdsTrain,covnet1,options);
在单 GPU 上训练。 正在初始化输入数据归一化。 |=============================================================================| |  轮  |  迭代  |    经过的时间     |  小批量准确度  |  验证准确度  |  小批量损失  |  验证损失  |  基础学习率  | |     |      |  (hh:mm:ss)  |          |         |         |        |         | |=============================================================================| |   1 |    1 |     00:00:04 |    7.03% |   9.56% |  3.0360 | 2.8614 |  0.0005 | |   1 |   30 |     00:00:06 |   54.69% |  51.04% |  1.5394 | 1.4985 |  0.0005 | |   1 |   50 |     00:00:07 |   57.81% |         |  1.2810 |        |  0.0005 | |   2 |   60 |     00:00:08 |   69.53% |  63.52% |  1.0615 | 1.1669 |  0.0005 | |   2 |   90 |     00:00:10 |   72.66% |  70.16% |  1.0254 | 0.9953 |  0.0005 | |   2 |  100 |     00:00:10 |   78.91% |         |  0.9027 |        |  0.0005 | |   3 |  120 |     00:00:11 |   74.22% |  74.52% |  0.8409 | 0.8648 |  0.0005 | |   3 |  150 |     00:00:13 |   81.25% |  78.84% |  0.7043 | 0.7388 |  0.0005 | |   4 |  180 |     00:00:15 |   90.63% |  82.28% |  0.4792 | 0.6454 |  0.0005 | |   4 |  200 |     00:00:15 |   82.03% |         |  0.5725 |        |  0.0005 | |   4 |  210 |     00:00:16 |   86.72% |  84.96% |  0.4985 | 0.5688 |  0.0005 | |   5 |  240 |     00:00:18 |   89.06% |  88.00% |  0.4597 | 0.4966 |  0.0005 | |   5 |  250 |     00:00:18 |   88.28% |         |  0.5131 |        |  0.0005 | |   5 |  270 |     00:00:19 |   92.19% |  89.64% |  0.4281 | 0.4395 |  0.0005 | |   6 |  300 |     00:00:21 |   94.53% |  91.04% |  0.3613 | 0.3951 |  0.0005 | |   6 |  330 |     00:00:23 |   92.19% |  91.72% |  0.3565 | 0.3614 |  0.0005 | |   6 |  348 |     00:00:24 |   95.31% |  92.52% |  0.2662 | 0.3416 |  0.0005 | |=============================================================================|
%% 步骤4:将训练好的网络用于对新的输入图像进行分类,并计算准确率
YPred = classify(net,imdsValidation);
YValidation = imdsValidation.Labels;
accuracy = sum(YPred == YValidation)/numel(YValidation)
accuracy =
0.926000000000000
在命令行中运行效果图:
accuracy =
0.938000000000000

采用Deep Network Designer实现迁移学习

调整网络结构
步骤1:加载预训练AlexNet网络
net= alexnet
net =
SeriesNetwork - 属性: Layers: [25×1 nnet.cnn.layer.Layer] InputNames: {'data'} OutputNames: {'output'}
步骤2:将网络导入Deep Network Designer设计器
命令行窗口中输入以下代码
deepNetworkDesigner %在命令行中操作
按Import按钮导入刚刚加载的网络,如图所示,单击OK。
可以看到整个网络结构以可视化的形式呈现在设计区中,每个彩色矩阵块代表一层,右侧显示网络属性。
https://ww2.mathworks.cn/help/deeplearning/gs/get-started-with-transfer-learning.html
迁移学习官方案例参考
https://ww2.mathworks.cn/help/deeplearning/ug/transfer-learning-with-deep-network-designer.html